#include "leos_thread.h"
#include "leos_hw.h"
#include "leos_service.h"

le_thread_t le_current_thread;

static void le_thread_cleanup_excu(le_thread_t thread)
{
    le_int32_t level = le_hw_interrupt_disable();

    if (thread->clean_up != LE_NULL) {
        thread->clean_up(thread);
    }

    le_hw_interrupt_enable(level);
}

/* 调用线程cleanup，调度系统中移除该线程，更新状态，关闭线程定时器 */
static void le_thread_exit(void)
{
    le_thread_t thread = le_current_thread;

    le_int32_t level = le_hw_interrupt_disable();

    le_thread_cleanup_excu(thread);

    le_schedule_remove_thread(thread);

    thread->state = LE_THREAD_STATE_CLOSE;

    le_timer_stop(&thread->thread_timer);

    le_schedule();

    le_hw_interrupt_enable(level);
}

/* 线程定时器超时回调函数，与 yield 相同将线程添加到就绪列表末尾，并调度 */
void le_thread_timeout_cb(void *parameter)
{
    le_thread_t thread = (le_thread_t)parameter;

    le_list_remove(&thread->tlist);

    le_schedule_insert_thread(thread);

    le_schedule();
}

void le_thread_init(le_thread_t     thread,
                    const char     *name,
                    void (*entry)(void *parameter),
                    void           *parameter,
                    void           *stack_start,
                    le_uint32_t     stack_size,
                    le_uint8_t      priority,
                    le_int32_t      tick)
{
    le_strncpy(thread->base.name, name, LE_NAME_MAX - 1);
    thread->base.flag           = LE_THREAD_STATE_INIT;
    le_list_init(&thread->base.list);

    le_list_init(&thread->tlist);

    thread->entry               = entry;
    thread->parameter           = parameter;
    thread->stack_addr          = stack_start;
    thread->stack_size          = stack_size;
    thread->sp                  = le_hw_stack_init(entry, parameter, 
                                                   stack_start + stack_size, 
                                                   le_thread_exit);

    thread->init_priority       = priority;
    thread->current_priority    = priority;

    thread->state               = LE_THREAD_STATE_INIT;
    thread->clean_up            = LE_NULL;
    
    thread->init_tick           = tick;
    thread->remaining_tick      = tick;

    le_timer_init(&thread->thread_timer, le_thread_timeout_cb, thread);
}


/* le_thread_yield 让出CPU使用权，并把当前线程添加到就绪链表末尾 */
void le_thread_yield(void)
{
    le_thread_t thread = le_current_thread;

    le_int32_t level = le_hw_interrupt_disable();

    /* 判断当前线程是否为 就绪状态 且 在就绪队列 且 就绪队列中大于等于2个线程 */
    if (thread->state == LE_THERAD_STATE_READY &&
        thread->tlist.next != thread->tlist.prev)
    {
        le_list_remove(&thread->tlist);

        le_list_insert_before(&thread->tlist, &le_thread_priority_table[thread->current_priority]);

        le_hw_interrupt_enable(level);

        le_schedule();

        return;
    }

    le_hw_interrupt_enable(level);
}

/* le_thread_resume 从就绪链表中删除了thread，停止了线程定时器，然后重新再添加到调度系统中 */
void le_thread_resume(le_thread_t thread)
{
    le_int32_t level = le_hw_interrupt_disable();

    /* 这里是为了防止任务挂在阻塞列表 */
    le_list_remove(&thread->tlist);

    le_timer_stop(&thread->thread_timer);

    le_schedule_insert_thread(thread);

    le_hw_interrupt_enable(level);
}

void le_thread_suspend(le_thread_t thread)
{
    le_int32_t level = le_hw_interrupt_disable();

    le_schedule_remove_thread(thread);

    le_timer_stop(&thread->thread_timer);

    le_hw_interrupt_enable(level);
}

void le_thread_startup(le_thread_t thread)
{
    thread->state = LE_THREAD_STATE_SUSPEND;
    
    le_thread_resume(thread);

    if (le_current_thread) {
        le_schedule();
    }
}

static void le_thread_sleep(le_tick_t tick)
{
    le_int32_t level = le_hw_interrupt_disable();

    le_thread_t thread = le_current_thread;

    le_thread_suspend(thread);

    le_timer_start(&thread->thread_timer, le_tick_get() + tick);

    le_schedule();

    le_hw_interrupt_enable(level);
}

void le_thread_mdelay(le_uint32_t ms)
{
    le_tick_t tick = ms * LE_TICKS_PER_SEC / 1000;

    le_thread_sleep(tick);
}


static struct le_thread idle;

static le_uint8_t le_thread_idle_stack[128];

void le_thread_idle_entry(void *parameter)
{
    while (1) {

    }
}

void le_thread_idle_init(void)
{
    le_thread_init(&idle, 
                   "idle", 
                   le_thread_idle_entry, 
                   LE_NULL, 
                   le_thread_idle_stack, 
                   sizeof(le_thread_idle_stack), 
                   LE_THREAD_PRIORITY_MAX - 1, 
                   32);

    le_thread_startup(&idle);
}